package com.travel.config.pool;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.validation.constraints.NotNull;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author: libin
 * Date: 2025/6/20 8:22
 * Description:
 **/
@Configuration
@EnableConfigurationProperties(ThreadPoolProperties.class)
public class ThreadPoolAutoConfiguration {

    Logger logger = LoggerFactory.getLogger(this.getClass());


    @Autowired
    ThreadPoolProperties threadPoolProperties;

    /**
     * 自定义线程池对象
     * <p>
     * 线程池中常用的阻塞队列：
     * 1）ArrayBlockQueue;
     * 2) LinkedBlockQueue;
     * <p>
     * ArrayBlockQueue and   LinkedBlockQueue区别
     * 1、底层数据结构不同
     * ArrayBlockQueue底层是由数组这种数据结构维护的。
     * LinkedBlockQueue区别底层是由链表这种数据结构维护的。
     * <p>
     * 2、队列大小容量不同
     * ArrayBlockQueue：有界阻塞队列
     * LinkedBlockQueue：无界阻塞队列（相对无界 并不是正无穷 Integer.MAX_VALUE）
     * <p>
     * 3、支持的并发度不同
     * ArrayBlockQueue：底层直接对这个队列进行加锁，因此读写这个队列的并发相对低一些。
     * LinkedBlockQueue：底层是正对操作这个元素的位置进行加锁，因此读写这个队列的并发相对高一些。
     * <p>
     * 4、LinkedBlockQueue在使用过程中如果不给这个队列一个大小限制 那么就可能会出现oom.
     */
    @Bean
    public ThreadPoolExecutor threadPoolExecutor() {

        Long corePoolSize = threadPoolProperties.getCorePoolSize();
        Long maxPoolSize = threadPoolProperties.getMaxPoolSize();
        Long timeOut = threadPoolProperties.getTimeOut();
        Long queueSize = threadPoolProperties.getQueueSize();


        /**
         * 自定义线程工厂
         */
        ThreadFactory myThreadFactory = new ThreadFactory() {


            AtomicInteger atomicInteger = new AtomicInteger(0);

            @Override
            public Thread newThread(@NotNull Runnable r) {
                // 自己创建了一个线程&&还把外面的任务接过来(更加的灵活管理线程)
                Thread thread = new Thread(r);
                thread.setName("【my-thread-pool-" + atomicInteger.incrementAndGet() + "】");
                return thread;
            }
        };

        /**
         * 自定义一个拒绝策略
         */
        RejectedExecutionHandler myRejectedExecutionHandler = new RejectedExecutionHandler() {
            @Override
            public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
                logger.info("任务进入了自定义的拒绝策略");
                throw new RejectedExecutionException("任务 " + r.toString() +
                        "被拒绝l " +
                        e.toString());
            }
        };

        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize.intValue(),
                maxPoolSize.intValue(),
                timeOut,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<Runnable>(queueSize.intValue()),
                myThreadFactory,
                myRejectedExecutionHandler
        );

        return threadPoolExecutor;
    }

    // 未来公司的线程池应该定义两套
    // 一套线程池是给普通接口使用（普通查询详情...）： 核心线程数  最大线程  阻塞队列参数都可以相对小一些
    // 另外一套线程池给核心接口使用(下单接口或者查询订单的接口...) 核心线程数  最大线程  阻塞队列参数都可以相对大一些


}